-- $Id: Jet.lua 3171 2008-11-06 09:06:29Z det $
-----------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------

local Jet = {}
Jet.__index = Jet

local jitShader
local tex --//screencopy
local timerUniform
-----------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------

function Jet.GetInfo()
  return {
    name      = "Jet",
    backup    = "", --// backup class, if this class doesn't work (old cards,ati's,etc.)
    desc      = "",

    layer     = 4, --// extreme simply z-ordering :x

    --// gfx requirement
    fbo       = true,
    shader    = true,
    distortion= true,
    atiseries = 2,
    ms        = -1,
    intel     = -1,
  }
end


Jet.Default = {
  layer = 4,
  life  = math.huge,
  repeatEffect  = true,

  emitVector    = {0,0,-1},
  pos           = {0,0,0}, --// not used
  width         = 4,
  length        = 50,
  distortion    = 0.02,
  animSpeed     = 1,

  texture1      = "bitmaps/GPL/Lups/perlin_noise.jpg", --// noise texture
  texture2      = ":c:bitmaps/GPL/Lups/jet.bmp",       --// jitter shape
}

-----------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------

local spGetGameSeconds = Spring.GetGameSeconds
local glUseShader = gl.UseShader
local glUniform   = gl.Uniform
local glTexture   = gl.Texture
local glCallList  = gl.CallList

function Jet:BeginDrawDistortion()
  glUseShader(jitShader)
    glUniform(timerUniform, spGetGameSeconds())
end

function Jet:EndDrawDistortion()
  glUseShader(0)
  glTexture(1,false)
  glTexture(2,false)
end

function Jet:DrawDistortion()
  glTexture(1,self.texture1) 
  glTexture(2,self.texture2) 

  glCallList(self.dList)
end

-----------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------

-- used if repeatEffect=true;
function Jet:ReInitialize()
  self.dieGameFrame = self.dieGameFrame + self.life
end

function Jet.Initialize()
  jitShader = gl.CreateShader({
    vertex = [[
      uniform float timer;

      varying float distortion;
      varying vec4 texCoords;

      const vec4 centerPos = vec4(0.0,0.0,0.0,1.0);

      // gl_vertex.xy := width/length
      // gl_vertex.zw := texcoord
      // gl_MultiTexCoord0.x  := (quad_width) / (quad_length) (used to normalize the texcoord dimensions)
      // gl_MultiTexCoord0.y  := distortion strength
      // gl_MultiTexCoord0.z  := animation speed
      // gl_MultiTexCoord1    := emit vector

      void main()
      {
        texCoords.st  = gl_Vertex.pq;
        texCoords.pq  = gl_Vertex.pq;
        texCoords.p  *= gl_MultiTexCoord0.x;
        texCoords.pq += timer*gl_MultiTexCoord0.z;

        gl_Position = gl_ModelViewMatrix * centerPos;
        vec3 dir3   = vec3(gl_ModelViewMatrix * gl_MultiTexCoord1) - gl_Position.xyz;
        vec3 v = normalize( dir3 );
        vec3 w = normalize( -vec3(gl_Position) );
        vec3 u = normalize( cross(w,v) );
        gl_Position.xyz += gl_Vertex.x*v + gl_Vertex.y*u;
        gl_Position      = gl_ProjectionMatrix * gl_Position;

        distortion = gl_MultiTexCoord0.y;
      }
    ]],
    fragment = [[
      uniform sampler2D noiseMap;
      uniform sampler2D mask;

      varying float distortion;
      varying vec4 texCoords;

      void main(void)
      {
          float opac    = texture2D(mask,texCoords.st).r;
          vec2 noiseVec = (texture2D(noiseMap, texCoords.pq).st - 0.5) * distortion * opac;
          gl_FragColor  = vec4(noiseVec.xy,0.0,gl_FragCoord.z);
      }

    ]],
    uniformInt = {
      noiseMap = 1,
      mask = 2,
    },
    uniform = {
      timer = 0,
    }
  })


  if (jitShader == nil) then
    print(PRIO_MAJOR,"LUPS->Jet: shader error: "..gl.GetShaderLog())
    return false
  end

  timerUniform = gl.GetUniformLocation(jitShader, 'timer')
end

function Jet:Finalize()
  if (gl.DeleteShader) then
    gl.DeleteShader(jitShader)
  end
end

-----------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------

local glMultiTexCoord = gl.MultiTexCoord
local glVertex        = gl.Vertex
local glCreateList    = gl.CreateList
local glDeleteList    = gl.DeleteList
local glBeginEnd      = gl.BeginEnd
local GL_QUADS        = GL.QUADS

local function BeginEndDrawList(self)
  local ev    = self.emitVector 
  glMultiTexCoord(0,self.width/self.length,self.distortion,0.2*self.animSpeed)
  glMultiTexCoord(1,ev[1],ev[2],ev[3],1)

  --// xy = width/length ; zw = texcoord
  local w = self.width
  local l = self.length
  glVertex(-l,-w, 1,0)
  glVertex(0, -w, 1,1)
  glVertex(0,  w, 0,1)
  glVertex(-l, w, 0,0)
end


function Jet:CreateParticle()
  self.dList = glCreateList(glBeginEnd,GL_QUADS,
                            BeginEndDrawList,self)

  --// used for visibility check
  self.radius = self.length

  self.dieGameFrame  = thisGameFrame + self.life
end

-----------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------

local MergeTable   = MergeTable
local setmetatable = setmetatable

function Jet.Create(Options)
  local newObject = MergeTable(Options, Jet.Default)
  setmetatable(newObject,Jet)  -- make handle lookup
  newObject:CreateParticle()
  return newObject
end

function Jet:Destroy()
  --gl.DeleteTexture(self.texture1)
  --gl.DeleteTexture(self.texture2)
  glDeleteList(self.dList)
end

-----------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------

return Jet